/*
 * snmp_oid.cpp
 *
 *  Created on: 2016-10-31
 *      Author: root
 */

#include"snmp_oid.h"
#include"snmp_asn.h"
#include<string.h>
#include<stdint.h>
#include<stdio.h>
#include<stdlib.h>
#include"PublicTool.h"
#include"PublicLog.h"
//将数据加入到队列
int AddSnmpDataInfo(SnmpPacket*Packet,SnmpDataInfo*DataInfo);
//读取类型值,返回下一跳位置
const char*ReadSnmpDataInfo(const char*data,int len,u_char type,SnmpDataInfo*DataInfo);
#if 0
int SnmpCopyOidName(uint32_t*dstName,const uint32_t*srcName,int oidLen){
    int i=0;
    while(i<oidLen){
		dstName[i]=srcName[i];
		i++;
    }
    return 0;
}
#endif
SnmpPacket*CreateSnmpPacket(int version,const char*community,u_char pdutype,int request_id){
    SnmpPacket*packet=(SnmpPacket*)malloc(sizeof(SnmpPacket));
    memset(packet,0,sizeof(SnmpPacket));
    packet->version=version;
    packet->community=strdup(community);
    packet->pdutype=pdutype;
    packet->request_id=request_id;
    return packet;
}
int AddSnmpDataInfo(SnmpPacket*Packet,SnmpDataInfo*DataInfo){
    if(Packet==NULL||DataInfo==NULL){
		WRONG("WRONG%s %d",__FUNCTION__,__LINE__);
		return 0;
    }
    if(Packet->data==NULL){
		Packet->data=DataInfo;
    }else{
		SnmpDataInfo*Pos=Packet->data;
		while(Pos->Next!=NULL)
			Pos=Pos->Next;
		Pos->Next=DataInfo;
	}
	return 0;
}
int AddSnmpRequestOid(SnmpPacket*Packet,const SnmpOidInfo oidinfo){
    SnmpDataInfo*tmp=(SnmpDataInfo*)malloc(sizeof(SnmpDataInfo));
    memset(tmp,0,sizeof(SnmpDataInfo));
	memcpy(tmp->oidName,oidinfo.oidName,sizeof(oidinfo.oidName[0])*oidinfo.oidLen);
    //SnmpCopyOidName(tmp->oidName,oidinfo.oidName,oidinfo.oidLen);
    tmp->oidLen=oidinfo.oidLen;
    tmp->valType=ASN_NULL;
    AddSnmpDataInfo(Packet,tmp);
    return 0;
}
/*
30 2f 包长2f
02 01 01 版本整形V2c  3
04 0d 65 77 63 61 63 68 65 2d 35 35 36 36 37 字符串ewcache-55667  15  2+strlen(ewcache-55667)
a1 1b 数据包大小1b  2
02 04 1f 15 ec b2请求ID521530546   6
02 01 00 错误状态0    3
02 01 00 错误偏移0    3
30 0e 请求数据总大小
30 0c 变量和值      2    11
06 08 2b 06 01 02 01 01 01 00 ObjectName 1.3.6.1.2.1.1.1.0
05 00 空
*/

int WriteSnmpPacket(SnmpPacket*Packet,char*databuff,int*len){
//构建每个包
do{
    SnmpDataInfo*Pos=Packet->data;
    while(Pos!=NULL){
		Pos->datalen=MakeAsnRequestData(Pos->data,0,Pos->oidName,Pos->oidLen);
		Packet->datalen+=Pos->datalen;
		Pos=Pos->Next;
    }
}while(0);
//团体号长度
    char communitydata[1024]={0};
    int  communitylen=MakeAsnStringData(communitydata,0,ASN_OCTET_STR,Packet->community,strlen(Packet->community));
//数据包长度
    char datalenbuff[16]={0};
    int  datalenbufflen=MakeAsnLengthData(datalenbuff,0,ASN_SEQUENCE,Packet->datalen);
//请求数据长度
    int  packetlen=datalenbufflen+Packet->datalen+3+3+6;
    char packetlenbuff[16]={0};
    int  packetlenbufflen=MakeAsnLengthData(packetlenbuff,0,Packet->pdutype,packetlen);
//总长度
    int  totallen=3+communitylen+packetlenbufflen+packetlen;
//开始构建包
    int headlen=MakeAsnLengthData(databuff,0,ASN_SEQUENCE,totallen);
    int Pos=headlen;
//写入版本号
    MakeAsnIntData(databuff+Pos,0,ASN_INTEGER,Packet->version,1);
    Pos+=3;
//写入团体号
    memcpy(databuff+Pos,communitydata,communitylen);
    Pos+=communitylen;
//写入包大小
    memcpy(databuff+Pos,packetlenbuff,packetlenbufflen);
    Pos+=packetlenbufflen;
//写入请求ID
    MakeAsnIntData(databuff+Pos,0,ASN_INTEGER,Packet->request_id,4);
    Pos+=6;
//错误状态0
    MakeAsnIntData(databuff+Pos,0,ASN_INTEGER,0,1);
    Pos+=3;
//错误位置0
    MakeAsnIntData(databuff+Pos,0,ASN_INTEGER,0,1);
    Pos+=3;
//数据总长度
    memcpy(databuff+Pos,datalenbuff,datalenbufflen);
    Pos+=datalenbufflen;
do{
    SnmpDataInfo*PosData=Packet->data;
    while(PosData!=NULL){
		memcpy(databuff+Pos,PosData->data,PosData->datalen);
		Pos+=PosData->datalen;
		PosData=PosData->Next;
    }
}while(0);
    return headlen+totallen;
}
/*
30 2f 包长2f
02 01 01 版本整形V2c  3
04 0d 65 77 63 61 63 68 65 2d 35 35 36 36 37 字符串ewcache-55667  15  2+strlen(ewcache-55667)
a1 1b 数据包大小1b  2
02 04 1f 15 ec b2请求ID521530546   6
02 01 00 错误状态0    3
02 01 00 错误偏移0    3
30 0e 请求数据总大小
30 0c 变量和值      2    11
06 08 2b 06 01 02 01 01 01 00 ObjectName 1.3.6.1.2.1.1.1.0
05 00 空
*/
SnmpPacket*ReadSnmpPacket(const char*buff,int len){
    SnmpPacket*packet=(SnmpPacket*)malloc(sizeof(SnmpPacket));
    memset(packet,0,sizeof(SnmpPacket));
    const char*Pos=buff;
    int datalen=0;
    Pos=ReadAsnSequenceLength(Pos,len,datalen);
//不是合理包	
	if((Pos+datalen)!=(buff+len)){
		free(packet);
		WRONG("收到非SNMP包");
		return NULL;
	}
    DEBUG("包总长度:%d",datalen);

    Pos=ReadAsnIntData(Pos,len,ASN_INTEGER,packet->version);
    DEBUG("版本号:%d",packet->version);

    Pos=ReadAsnLengthData(Pos,len,ASN_OCTET_STR,datalen);
    packet->community=(char*)malloc(datalen+1);
    memset(packet->community,0,datalen+1);
    memcpy(packet->community,Pos,datalen);
    DEBUG("团体号长度:%d 内容:%s",datalen,packet->community);
    Pos+=datalen;

    char PduType=Pos[0];
    Pos=ReadAsnLengthData(Pos,len,PduType,datalen);
    DEBUG("请求数据包长度:%d 请求类型:0x%hhx",datalen,PduType);

    Pos=ReadAsnIntData(Pos,len,ASN_INTEGER,packet->request_id);
    DEBUG("请求ID:%u",packet->request_id);

    Pos=ReadAsnIntData(Pos,len,ASN_INTEGER,packet->error_status);
    DEBUG("错误状态:%d",packet->error_status);

    Pos=ReadAsnIntData(Pos,len,ASN_INTEGER,packet->error_index);
    DEBUG("错误偏移:%d",packet->error_index);

    Pos=ReadAsnSequenceLength(Pos,len,datalen);
    DEBUG("请求内容总长度:%d",datalen);
    const char*DataStartPos=Pos;
    int DataTotalLen=datalen;
    while(Pos-DataStartPos<DataTotalLen){
		const char*CheckPos=Pos;
		SnmpDataInfo*TmpData=(SnmpDataInfo*)malloc(sizeof(SnmpDataInfo));
		memset(TmpData,0,sizeof(SnmpDataInfo));
		Pos=ReadAsnSequenceLength(Pos,len,datalen);
		//DEBUG("请求内容长度:%d",datalen);
		Pos=ReadAsnObjectIDData(Pos,len,TmpData->oidName,TmpData->oidLen);
		do{
			char buff[1024]={0};
			MakeSnmpOid(buff,TmpData->oidName,TmpData->oidLen);
			DEBUG("请求内容长度:%d 请求OID:%s",datalen,buff);
		}while(0);
		u_char DataType=(u_char)Pos[0];
		TmpData->valType=DataType;
		Pos=ReadSnmpDataInfo(Pos,len,DataType,TmpData);
		AddSnmpDataInfo(packet,TmpData);
//位置没变，该包可能有问题		
		if(Pos==CheckPos){
			packet=FreeSnmpPacket(packet);
			WRONG("收到非SNMP包2");
			return NULL;
		}
    }
    return packet;
}
SnmpPacket*FreeSnmpPacket(SnmpPacket*Packet){
    if(Packet==NULL)return NULL;
    SnmpDataInfo*Pos=Packet->data;
    while(Pos!=NULL){
		SnmpDataInfo*PosNow=Pos;
		if(Pos->valType==ASN_OCTET_STR){
			if(Pos->value.valstr!=NULL){
				free(Pos->value.valstr);
				Pos->value.valstr=NULL;
            }
			Pos->valType=ASN_NULL;
        }
		Pos=Pos->Next;
		free(PosNow);
    }
    if(Packet->community){
		free(Packet->community);
		Packet->community=NULL;
    }
    free(Packet);
    return NULL;
}
void MakeSnmpOid(char*buff,uint32_t*oidName,int oidLen){
    int i=0;
    for(i=0;i<oidLen;i++){
        char tmp[16]={0};
        sprintf(tmp,".%u",oidName[i]);
        strcat(buff,tmp);
    }
}
int OidNameBaseCmp(uint32_t oidName[],int oidLen,uint32_t oidName2[],int oidLen2){
    if(oidLen<oidLen2)return 1;
    if(oidLen>oidLen2)return -1;
    int i=0;
    while(i<oidLen){
		if(oidName[i]<oidName2[i])return 1;
		if(oidName[i]>oidName2[i])return -1;
		i++;
    }
    return 0;
}
int OidNameCmp(SnmpDataInfo*data,SnmpOidInfo oidinfo){
    return OidNameBaseCmp(data->oidName,data->oidLen,oidinfo.oidName,oidinfo.oidLen);
}
int OidNameNCmp(SnmpDataInfo*data,SnmpOidInfo oidinfo){
    return OidNameBaseCmp(data->oidName,data->oidLen<oidinfo.oidLen?data->oidLen:oidinfo.oidLen,oidinfo.oidName,oidinfo.oidLen);
}
SnmpOidInfo OidNameAddIP(SnmpOidInfo oidinfo,const char*IP){
    u_char temp[4];
    sscanf(IP,"%hhu.%hhu.%hhu.%hhu",&temp[0],&temp[1],&temp[2],&temp[3]);
    oidinfo.oidName[oidinfo.oidLen++]=temp[0];
    oidinfo.oidName[oidinfo.oidLen++]=temp[1];
    oidinfo.oidName[oidinfo.oidLen++]=temp[2];
    oidinfo.oidName[oidinfo.oidLen++]=temp[3];
    return oidinfo;
}
void ShowSnmpPacket(SnmpPacket*Packet){
    if(Packet==NULL){
        WRONG("内容为NULL");
        return;
    }
    INFO("VER:%d COMMUNITY:%s ID:%u",Packet->version,Packet->community,Packet->request_id);
    INFO("TYPE:%hhu STATUS:%hhu index:%hhu",Packet->pdutype,Packet->error_status,Packet->error_index);
    SnmpDataInfo*Pos=Packet->data;
    while(Pos!=NULL){
		char buff[1024]={0};
		MakeSnmpOid(buff,Pos->oidName,Pos->oidLen);
		INFO("Oid:%s Type:%s(%hhu) Length:%d Value:%s",buff,GetAsnTypeName(Pos->valType),Pos->valType,Pos->valLen,Pos->data);
		Pos=Pos->Next;
    }
}
